import cn.hum.service.SayHello;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @Author: huangzhibin
 * @Description:
 * @Date: Created in 2021-01-10
 * @Modified By:
 */
public class RpcService {
    private static final int port = 20000;
    private static final InetSocketAddress register = new InetSocketAddress("127.0.0.1", 10001);
    private static final ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

    public static void prepare() {
        System.out.println("开启注册服务！");

        ObjectOutputStream outputStream = null;
        ObjectInputStream inputStream = null;
        try {
            Socket socket = new Socket();
            socket.connect(register);
            outputStream = new ObjectOutputStream(socket.getOutputStream());
            outputStream.writeUTF("register");
            outputStream.writeUTF(SayHello.class.getName());
            outputStream.writeInt(port);
            outputStream.flush();

            //获取应答
            inputStream = new ObjectInputStream(socket.getInputStream());
            if (inputStream.readBoolean()) {
                System.out.println("注册服务成功！");
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {

            try {
                if (outputStream != null) outputStream.close();
                if (inputStream != null) inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


    }

    public static void start(int port) {
        prepare();
        try (ServerSocket serverSocket = new ServerSocket(port)) {
            System.out.println("服务启动...");

            while (true) {
                Socket client = serverSocket.accept();
                executor.execute(new RpcTask(client));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private static class RpcTask implements Runnable {
        private final Socket socket;

        private RpcTask(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            try (ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream());
                 ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream())) {

                String className = inputStream.readUTF();
                String methodName = inputStream.readUTF();
                //因为本身是数组，不能直接用Object，需要进行强转，不然会报错
                Class<?>[] paramsTypes = (Class<?>[]) inputStream.readObject();
                Object[] params = (Object[]) inputStream.readObject();

                Class<?> targetClass = Class.forName(className);
                Object service = targetClass.newInstance();

                Method method = targetClass.getMethod(methodName, paramsTypes);
                Object invoke = method.invoke(service, params);

                outputStream.writeObject(invoke);
                outputStream.flush();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }

        }
    }
}
